﻿using Minotaur.App.Core;
using Minotaur.App.Core.Mvvm;
using Minotaur.App.Core.Redis;
using Minotaur.App.Domains.Dto.Flow;
using Minotaur.App.Domains.Enum;
using Minotaur.App.Modules.FlowProcess.Control;
using Newtonsoft.Json;
using Prism.Commands;
using Prism.Mvvm;
using Prism.Regions;
using ServiceStack;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Minotaur.App.Core;
using System.Runtime.InteropServices;
using System.Windows.Media;
using Minotaur.App.Core.Contrls;
using System.Windows.Markup;
using System.Windows.Shapes;
using MaterialDesignThemes.Wpf;
using System.Security.Cryptography.X509Certificates;

namespace Minotaur.App.Modules.FlowProcess.ViewModels
{
    /// <summary>
    /// 表单设计视图类
    /// </summary>
    public class ProcessDesignedViewModel : WindowComputeViewModel
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="regionManager"></param>
        /// <param name="dbContext"></param>
        /// <param name="_redisClient"></param>
        public ProcessDesignedViewModel(IRegionManager regionManager, IDbContext dbContext, IRedisClient _redisClient) : base(regionManager, dbContext, _redisClient)
        {

        }

        public Canvas ProcessDesignCanvas { get; set; }

        /// <summary>
        /// 流程信息
        /// </summary>
        public FlowInfoDto FlowInfoDto { get => _FlowInfoDto; set => SetProperty(ref _FlowInfoDto, value); }


        /// <summary>
        /// 流程信息
        /// </summary>
        private FlowInfoDto _FlowInfoDto = new FlowInfoDto();



        #region 方法命名定义
        public ICommand AddFlowNodeCommand => new DelegateCommand<object>(AddFlowNodeAction);
        private void AddFlowNodeAction(object obj)
        {
            if (obj is null) return;
            MenuItem menuItem = obj as MenuItem;
            var objValue = menuItem?.Tag;
            PropType propType = (PropType)(int.Parse(objValue?.ToString()));
            if (this.FlowInfoDto.Nodes.Any(p => p.Prop == propType) && (propType == PropType.StartNode || propType == PropType.EndNode))
            {
                return;
            }
            Point p = menuItem.TranslatePoint(new Point(), this.ProcessDesignCanvas);

            FlowStepInfoDto stepInfoDto = new FlowStepInfoDto()
            {
                StepId = HashUtilsHelper.GetLongHashCode(),
                CNName = propType == PropType.AccessNode || propType == PropType.ApprovalNode ? "审批节点" : "",
                ENName = propType == PropType.AccessNode || propType == PropType.ApprovalNode ? "审批节点" : "",
                Prop = propType,
                VersionId = this.FlowInfoDto.FormVersionId,
                ToLeft = p.X,
                ToTop = p.Y - 80,
                Coordinate = new double[] { p.X, p.Y - 80 }.ToSafeJson()
            };
            this.FlowInfoDto.Nodes.Add(stepInfoDto);
            GenerateCanvasChilds(stepInfoDto);
        }

        /// <summary>
        /// 打开流程树形
        /// </summary>
        public ICommand OpendFlowPropertyCommand => new DelegateCommand(OpendFlowPropertyAction);

        private void OpendFlowPropertyAction()
        {
            MessageBox.Show(this.FlowInfoDto.ToSafeJson());
        }
        #endregion
        #region 方法执行 

        /// <summary>
        /// 组装node参数
        /// </summary>
        /// <param name="item"></param>
        /// <exception cref="NotImplementedException"></exception>
        private void GenerateCanvasChilds(FlowStepInfoDto item)
        {
            PropType prop = item.Prop.Value;
            double[] PointAt = JsonConvert.DeserializeObject<double[]>(item.Coordinate);
            var flowStepInfo = new FlowStepInfoDto()
            {
                CNName = item.CNName,
                Coordinate = item.Coordinate,
                ENName = item.ENName,
                Prop = item.Prop,
                StepId = item.StepId,
                VersionId = item.VersionId,
                ToLeft = PointAt.Any() ? PointAt[0] : 0,
                ToTop = PointAt.Any() ? PointAt[1] : 0,
            };
            switch (prop)
            {
                case PropType.StartNode:
                    StartNodeControl nodeControl = new StartNodeControl(flowStepInfo);
                    nodeControl.OpendNodeClick += OpendNodeClick;
                    nodeControl.DeleteNodeEventClick += DeleteNodeEventClick;
                    nodeControl.NodeMoveDropEventClick += NodeMoveDropEventClick;
                    this.ProcessDesignCanvas.Children.Add(nodeControl);
                    break;
                case PropType.BranchNode:
                case PropType.EndBranchNode:
                    var branchNodeControl = new BranchNodeControl(flowStepInfo);
                    branchNodeControl.AddLineEventClick += AddLineEventClick;
                    branchNodeControl.NodeMoveDropEventClick += NodeMoveDropEventClick;
                    branchNodeControl.OpendNodeClick += OpendNodeClick;
                    branchNodeControl.DeleteNodeEventClick += DeleteNodeEventClick;
                    this.ProcessDesignCanvas.Children.Add(branchNodeControl);
                    break;
                case PropType.ConditionsNode:
                    ConditionsNodeControl conditionsNode = new ConditionsNodeControl(flowStepInfo);
                    conditionsNode.AddLineEventClick += AddLineEventClick;
                    conditionsNode.NodeMoveDropEventClick += NodeMoveDropEventClick;
                    conditionsNode.OpendNodeClick += OpendNodeClick;
                    conditionsNode.DeleteNodeEventClick += DeleteNodeEventClick;
                    this.ProcessDesignCanvas.Children.Add(conditionsNode);
                    break;
                case PropType.ApprovalNode:
                case PropType.AccessNode:
                    NodeControl node = new NodeControl(flowStepInfo);
                    node.OpendNodeClick += OpendNodeClick;
                    node.DeleteNodeEventClick += DeleteNodeEventClick;
                    node.AddLineEventClick += AddLineEventClick;
                    node.NodeMoveDropEventClick += NodeMoveDropEventClick;
                    this.ProcessDesignCanvas.Children.Add(node);
                    break;
                case PropType.EndNode:
                    var endNodeControl = new EndNodeControl(flowStepInfo);
                    endNodeControl.AddLineEventClick += AddLineEventClick;
                    endNodeControl.NodeMoveDropEventClick += NodeMoveDropEventClick;
                    endNodeControl.DeleteNodeEventClick += DeleteNodeEventClick;
                    this.ProcessDesignCanvas.Children.Add(endNodeControl);
                    break;
                default:
                    break;
            }
        }

        private void DeleteNodeEventClick1(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("1");
        }

        /// <summary>
        /// 节点拖动事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <exception cref="NotImplementedException"></exception>
        private void NodeMoveDropEventClick(object sender, RoutedEventArgs e)
        {
            FlowStepInfoDto flowStepInfo = e.OriginalSource as FlowStepInfoDto;
            #region 连线来自于节点
            List<FlowLineDto> flowLineDtos = this.FlowInfoDto.Lines.Where(o => o.StartId == flowStepInfo.StepId).ToList();
            UserControl userControl = (UserControl)sender;
            if (flowLineDtos.Any())
            {
                List<FlowLineControl1> lineControls = CoordinateUilts.GetChildObjects<FlowLineControl1>(this.ProcessDesignCanvas).Where(o => o.StartId == flowStepInfo.StepId).ToList();
                List<Button> buttons = CoordinateUilts.GetChildObjects<Button>(userControl).ToList();
                for (int i = 0; i < lineControls.Count; i++)
                {
                    var line = flowLineDtos.FirstOrDefault(p => p.LinkId == lineControls[i].FlowLineDtos.LinkId);
                    if (line is null) continue;
                    Button statrBtn = buttons.FirstOrDefault(o => (o.Tag + "") == line.StartLocation.ToString());
                    if (statrBtn is null) continue;
                    double[] coordinates = CoordinateUilts.ComputeStartNodeCoordinate(flowStepInfo.Prop.Value, flowStepInfo.Coordinate, userControl.ActualWidth, userControl.ActualHeight, line.StartLocation.ToString());
                    line.StartAt = coordinates.ToSafeJson();
                    double[] endCoordinates = JsonConvert.DeserializeObject<double[]>(line.EndAt);
                    lineControls[i].lineMain.Points = new PointCollection() { new Point() { X = coordinates[0], Y = coordinates[1] }, new Point() { X = endCoordinates[0], Y = endCoordinates[1] } };
                    ControlCommon.CalculateArrow(lineControls[i].lineTopArrow, new Point() { X = coordinates[0], Y = coordinates[1] }, new Point() { X = endCoordinates[0], Y = endCoordinates[1] });
                }
            }
            #endregion
            #region 连线结束节点
            List<FlowLineDto> endflowLineDtos = this.FlowInfoDto.Lines.Where(o => o.EndId == flowStepInfo.StepId).ToList();
            if (endflowLineDtos.Any())
            {
                List<FlowLineControl1> endLineContrls = CoordinateUilts.GetChildObjects<FlowLineControl1>(this.ProcessDesignCanvas).Where(o => o.EndId == flowStepInfo.StepId).ToList();
                List<Button> buttons = CoordinateUilts.GetChildObjects<Button>(userControl).ToList();
                for (int i = 0; i < endLineContrls.Count; i++)
                {
                    var line = endflowLineDtos.FirstOrDefault(p => p.LinkId == endLineContrls[i].FlowLineDtos.LinkId);
                    if (line is null) continue;
                    Button statrBtn = buttons.FirstOrDefault(o => (o.Tag + "") == line.EndLocation.ToString());
                    if (statrBtn is null) continue;
                    double[] endCoordinates = CoordinateUilts.ComputeEndNodeCoordinate(flowStepInfo.Prop.Value, flowStepInfo.Coordinate, userControl.ActualWidth, userControl.ActualHeight, line.EndLocation.ToString());
                    line.EndAt = endCoordinates.ToSafeJson();
                    double[] startCoordinates = JsonConvert.DeserializeObject<double[]>(line.StartAt);
                    endLineContrls[i].lineMain.Points = new PointCollection() { new Point() { X = startCoordinates[0], Y = startCoordinates[1] }, new Point() { X = endCoordinates[0], Y = endCoordinates[1] } };
                    ControlCommon.CalculateArrow(endLineContrls[i].lineTopArrow, new Point() { X = startCoordinates[0], Y = startCoordinates[1] }, new Point() { X = endCoordinates[0], Y = endCoordinates[1] });
                }
            }
            #endregion
        }

        /// <summary>
        /// 新增连线
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <exception cref="NotImplementedException"></exception>
        private void AddLineEventClick(object sender, RoutedEventArgs e)
        {

            AddNewLineParamaterDto flowLineDto = e.OriginalSource as AddNewLineParamaterDto;

            var newLine = this.FlowInfoDto.Lines.FirstOrDefault(o => o.StartId == flowLineDto.FlowLine.StartId && o.EndId == flowLineDto.FlowLine.EndId);
            PackIcon packIcon = new PackIcon()
            {
                Background = new SolidColorBrush(Colors.Snow),
                Kind = PackIconKind.Close,
                Foreground = new SolidColorBrush(Colors.Snow),
            };
            PackIcon endPackIcon = new PackIcon()
            {
                Background = new SolidColorBrush(Colors.Snow),
                Kind = PackIconKind.Close,
                Foreground = new SolidColorBrush(Colors.Snow),
            };
            if (newLine is null)
            {
                FlowLineControl1 flowLine = new FlowLineControl1(flowLineDto.FlowLine, flowLineDto.StartButton, flowLineDto.EndButton);
                flowLine.OpendLineClick += OpendLineClick;
                flowLine.DeleteLineEventClick += DeleteLineEventClick;
                this.ProcessDesignCanvas.Children.Add(flowLine);
                this.FlowInfoDto.Lines.Add(flowLineDto.FlowLine);
                //flowLineDto.StartButton.Content = packIcon;
                //flowLineDto.EndButton.Content = endPackIcon;
            }
            else
            {
                FlowLineControl1 endLineContrls = CoordinateUilts.GetChildObjects<FlowLineControl1>(this.ProcessDesignCanvas).FirstOrDefault(o => o.StartId == flowLineDto.FlowLine.StartId && o.EndId == flowLineDto.FlowLine.EndId);
                if (endLineContrls != null)
                {
                    #region 绘制连线
                    newLine.StartAt = flowLineDto.FlowLine.StartAt;
                    newLine.EndAt = flowLineDto.FlowLine.EndAt;
                    double[] startCoordinates = JsonConvert.DeserializeObject<double[]>(newLine.StartAt);
                    double[] endCoordinates = JsonConvert.DeserializeObject<double[]>(newLine.EndAt);
                    endLineContrls.lineMain.Points = new PointCollection() { new Point() { X = startCoordinates[0], Y = startCoordinates[1] }, new Point() { X = endCoordinates[0], Y = endCoordinates[1] } };
                    ControlCommon.CalculateArrow(endLineContrls.lineTopArrow, new Point() { X = startCoordinates[0], Y = startCoordinates[1] }, new Point() { X = endCoordinates[0], Y = endCoordinates[1] });
                    #endregion
                    //#region 移动连接点
                    //List<Button> btns = CoordinateUilts.GetChildObjects<Button>(flowLineDto.StartButton.Parent);
                    //Button startBtn = btns.FirstOrDefault(o => (o.Tag + "") == newLine.StartLocation.ToString());
                    //if (startBtn != null)
                    //    startBtn.Content = null;
                    //List<Button> endbtns = CoordinateUilts.GetChildObjects<Button>(flowLineDto.EndButton.Parent);
                    //Button endBtn = endbtns.FirstOrDefault(o => (o.Tag + "") == newLine.EndLocation.ToString());
                    //if (endBtn != null)
                    //    endBtn.Content = null;
                    //#endregion
                    newLine.StartLocation = flowLineDto.FlowLine.StartLocation;
                    newLine.EndLocation = flowLineDto.FlowLine.EndLocation;
                }
                //flowLineDto.StartButton.Content = packIcon;
                //flowLineDto.EndButton.Content = endPackIcon;
            }
            //List<Button> allBtns = GetChildObjects<Button>(this.ProcessDesignCanvas).Where(o => new string[] { "left", "right", "top", "bottom" }.Contains(o.Tag + "")).ToList();
            //allBtns.ForEach(o => o.Content = null);
        }

        /// <summary>
        /// 移除连线
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <exception cref="NotImplementedException"></exception>
        private void DeleteLineEventClick(object sender, RoutedEventArgs e)
        {
            FlowLineControl1 flowLine = sender as FlowLineControl1;
            FlowLineDto flowLineDto = e.OriginalSource as FlowLineDto;
            this.ProcessDesignCanvas.Children.Remove(flowLine);
            this.FlowInfoDto.Lines.Remove(flowLineDto);
            flowLine.StartButton.Content = null;
            flowLine.EndButton.Content = null;
        }

        private void OpendLineClick(object sender, RoutedEventArgs e)
        {
            MessageBox.Show(e.OriginalSource.ToSafeJson());
        }

        /// <summary>
        /// 删除节点
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <exception cref="NotImplementedException"></exception>
        private void DeleteNodeEventClick(object sender, RoutedEventArgs e)
        {
            #region 删除相应的节点信息
            UserControl startNode = sender as UserControl;
            FlowStepInfoDto stepInfoDto = startNode.DataContext as FlowStepInfoDto;
            this.ProcessDesignCanvas.Children.Remove(startNode);
            this.FlowInfoDto.Nodes = this.FlowInfoDto.Nodes.Where(o => o.StepId != stepInfoDto.StepId).ToList();
            #endregion

            #region 删除节点前后连线
            List<FlowLineControl1> lineControls = CoordinateUilts.GetChildObjects<FlowLineControl1>(ProcessDesignCanvas);
            var deleteLines = lineControls.Where(o => o.StartId == stepInfoDto.StepId || o.EndId == stepInfoDto.StepId).ToList();
            this.FlowInfoDto.Lines = this.FlowInfoDto.Lines.Where(o => o.StartId != stepInfoDto.StepId && o.EndId != stepInfoDto.StepId).ToList();
            if (deleteLines.Any())
            {
                for (int i = 0; i < deleteLines.Count; i++)
                {
                    if (!lineControls.Any(o =>
                    o.FlowLineDtos.LinkId != deleteLines[i].FlowLineDtos.LinkId
                    && (
                    o.StartButton == deleteLines[i].StartButton
                    ||
                    o.EndButton == deleteLines[i].StartButton
                    )))
                    {
                        deleteLines[i].StartButton.Content = null;
                    }
                    if (!lineControls.Any(o =>
                    o.FlowLineDtos.LinkId != deleteLines[i].FlowLineDtos.LinkId
                    && (
                    o.StartButton == deleteLines[i].EndButton
                    ||
                    o.EndButton == deleteLines[i].EndButton
                    )))
                    {
                        deleteLines[i].EndButton.Content = null;
                    }
                    this.ProcessDesignCanvas.Children.Remove(deleteLines[i]);
                }
            }
            #endregion
        }

        private void OpendNodeClick(object sender, RoutedEventArgs e)
        {
            UserControl startNode = sender as UserControl;
            FlowStepInfoDto stepInfoDto = startNode.DataContext as FlowStepInfoDto;
            MessageBox.Show(stepInfoDto.ToSafeJson());
        }

        public override void InitData()
        {
            OpendLoading = true;
            this.ProcessDesignCanvas.Children.Clear();
            foreach (var item in FlowInfoDto.Nodes)
            {
                GenerateCanvasChilds(item);
            }
            OpendLoading = false;
        }


        #endregion
    }
}
